/*
 * @Author: fhw
 * @Date: 2022-07-18 10:30:37
 * @LastEditors: Please set LastEditors
 * @LastEditTime: 2023-02-07 14:30:58
 * @Description:
 */
import {
  HttpException,
  HttpStatus,
  Injectable,
  UseFilters,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Between, LessThan, Like, MoreThan, Repository } from 'typeorm';
import {
  ArticleIdAndTitle,
  ArticleInfo,
  ArticleList,
  ArticleResult,
} from './entities/article.entity';

import { clone, equals, isEmpty, isNil } from 'ramda';
import {
  UpdateArticleThumbsUpDto,
  ArticlePageDto,
  CreateUpdateArticleDto,
  ArticleInfoDto,
} from './dto/article.dto';
import { HttpExceptionFilter } from 'src/common/http-exception.filter';
import { getPagination, throwHttp } from 'src/utlis';
import { stringify } from 'querystring';
import { IdDto } from 'src/common/dto/dto';
import { isTrue } from 'src/utlis/tools';
import { JwtService } from '@nestjs/jwt';
import { TokenDto } from 'src/common/auth/constants';

const reg = '!\\[.*\\]\\(.*\\)';
@Injectable()
export class ArticleService {
  constructor(
    @InjectRepository(ArticleList)
    private articleRepository: Repository<ArticleList>,
    private readonly jwtService: JwtService,
  ) { }
  @UseFilters(new HttpExceptionFilter())
  async getArticlePage(params: ArticlePageDto, path: string = 'page'): Promise<ArticleResult> {
    const {
      title,
      categories,
      tags,
      status,
      createTimeStart,
      createTimeEnd,
    } = params;
    const { pageSize, pageNum } = getPagination({ pageSize: params.pageSize, pageNum: params.pageNum })
    const where: ArticlePageDto = {
      title: Like(`%${title ?? ''}%`),
      status,
    };
    if (categories) {
      where.categories = Like(`%${categories ?? ''}%`)
    }
    if (tags) {
      where.tags = Like(`%${tags ?? ''}%`)
    }
    // 时间筛选
    if (!isNil(createTimeStart) && isNil(createTimeEnd)) {
      where.date = Between(createTimeStart, createTimeEnd);
    }
    const [data, total] = await this.articleRepository.findAndCount({
      where,
      skip: pageNum * pageSize,
      take: pageSize,
      order: { date: 'DESC' },
      relations: [],
      cache: true,
      select: ['id', 'title', 'categories', 'createBy', 'createById', 'date', 'excerpt', 'photos', 'read', 'status',
        'status', 'tags', 'thumbUp', 'updateDate']
    });
    const num = Math.ceil(total / pageSize)
    const pageNumber = pageNum + 1
    const paramsData = clone(params)
    delete paramsData.pageNum
    delete paramsData.pageSize
    return {
      data: data.map(item => {
        return item.processReturnedData()
      }),
      total,
      pageSize,
      pageNum: pageNumber,
      prev: pageNumber < num && pageNumber < 0 ? undefined : pageNumber - 1,
      prev_link: pageNumber - 1 == 1 ? (equals(path, 'path') ? '/' : `/${path}?${stringify(paramsData as any)}`) : this.getCurrentUrl(path, pageNumber - 1, paramsData),
      next: pageNumber < num ? pageNumber : undefined,
      next_link: this.getCurrentUrl(path, pageNumber + 1, paramsData),
    };
  }
  getCurrentUrl(path: string, pageNumber: number, params = {}): string {
    return `/${path}?${isTrue(params) ? `${stringify(params as any)}&` : ''}pageNum=${pageNumber}`
  }
  // 最新文章
  @UseFilters(new HttpExceptionFilter())
  async getArticleLately(): Promise<ArticleIdAndTitle[]> {
    return await this.articleRepository.find({
      skip: 0,
      take: 5,
      where: { status: '1' },
      order: { id: 'DESC' },
      select: ['id', 'title'],
    });
  }
  // 热门文章
  @UseFilters(new HttpExceptionFilter())
  async getArticleHot(): Promise<ArticleIdAndTitle[]> {
    const data = await this.articleRepository.find({
      skip: 0,
      take: 5,
      where: { status: '1' },
      order: { read: 'DESC' },
      select: ['id', 'title'],
    });
    return data
  }
  // 文章详情
  @UseFilters(new HttpExceptionFilter())
  async getArticleInfo({ id, categories, title }: ArticleInfoDto): Promise<ArticleInfo> {
    const data = await this.articleRepository.findOne({
      where: { id, title },
      relations: ['createBy'],
    });
    if (isNil(data) || isEmpty(data)) {
      throwHttp('文章不存在')
    }
    const prev = await this.articleRepository.findOne({
      where: {
        categories,
        id: LessThan(id),
        status: '1'
      },
      select: ['id', 'title'],
      order: { date: 'DESC' },
    });
    const next = await this.articleRepository.findOne({
      where: {
        categories,
        id: MoreThan(id),
        status: '1'
      },
      select: ['id', 'title'],
      order: { date: 'DESC' },
      cache: true,
    });
    return {
      data: data.processReturnedData(),
      prev,
      next,
    };
  }
  // 更新点赞数
  @UseFilters(new HttpExceptionFilter())
  async updateArticleThumbsUp({
    id,
  }: UpdateArticleThumbsUpDto): Promise<string> {
    const { data } = await this.getArticleInfo({ id });
    try {
      await this.articleRepository
        .createQueryBuilder()
        .update('article')
        .set({
          thumbUp: data.thumbUp + 1,
        })
        .where('id = :id', { id })
        .execute();
      return '更新成功';
    } catch (error) {
      throwHttp(error.message)
    }
  }
  // 创建更新文章入口
  @UseFilters(new HttpExceptionFilter())
  async createUpdateArticle(params: CreateUpdateArticleDto, headers): Promise<{ msg: string, data: ArticleList }> {
    try {
      const article = new ArticleList();
      const token = headers.authorization.split(' ');
      if (!isTrue(token)) {
        throwHttp('获取token失败');
        return
      }
      const operatorBy: TokenDto = this.jwtService.decode(token[1]) as TokenDto;
      if (equals(params.status, '1')) {
        if (isNil(params.title) || isEmpty(params.title)) {
          throwHttp('标题不能为空')
        }
        if (isNil(params.content) || isEmpty(params.content)) {
          throwHttp('文章内容不能为空')
        }
      }
      const { id } = params
      if (isTrue(id)) {
        await this.getArticleInfo({ id });
      }
      article.title = params.title;
      article.id = id;
      article.content = params.content;
      article.tags = JSON.stringify(params.tags);
      article.categories = JSON.stringify(params.categories);
      article.excerpt = params.excerpt;
      article.photos = params.photos;
      article.status = params.status;
      article.createById = operatorBy.userId;
      const result = await this.articleRepository.manager.save(article);
      return {
        msg: '成功',
        data: result
      };
    } catch (error) {
      throwHttp(error.message)
    }
  }
  // 删除文章
  @UseFilters(new HttpExceptionFilter())
  async deleteArticle({ id }: IdDto) {
    try {
      const { data } = await this.getArticleInfo({ id });
      await this.articleRepository.remove(data);
      return '删除成功';
    } catch (error) {
      throwHttp(error.message)
    }
  }
  // 更新阅读量
  @UseFilters(new HttpExceptionFilter())
  async updateArticleReadCount({ id }: IdDto) {
    const { data } = await this.getArticleInfo({ id });
    try {
      await this.articleRepository
        .createQueryBuilder()
        .update('article')
        .set({
          read: data.read + 1,
        })
        .where('id = :id', { id })
        .execute();
      return '更新成功';
    } catch (error) {
      throwHttp(error.message)
    }
  }
}
